package com.zff.rental.config;


import com.zff.rental.common.Result;
import com.zff.rental.common.ResultCode;
import lombok.extern.log4j.Log4j2;
import org.springframework.dao.DataAccessException;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

import java.net.ConnectException;
import java.sql.SQLException;
import java.util.stream.Collectors;

/**
 * 异常处理器
 *
 * @author HCY
 */
@Log4j2
@RestControllerAdvice(annotations = {RestController.class, Controller.class})
public class BusinessExceptionHandler {
    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public Result<Object> defaultExceptionHandler(Exception e) {
        String message = e.getMessage();
        if (message == null || message.isEmpty()) {
            message = "未知错误";
        }
        return Result.error(message);
    }

    /**
     * 数据库操作出现异常
     */
    @ExceptionHandler(value = {SQLException.class, DataAccessException.class})
    @ResponseBody
    @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
    public Result<Object> systemError(DataAccessException e) {
        String errorMsg = e.getMessage();
        if (errorMsg == null && e.getCause() != null) {
            errorMsg = e.getCause().getMessage();
        }
        log.error("数据库异常{}, {}", e.getClass(), errorMsg);
        return Result.of(ResultCode.EXCEPTION_DATA_ACCESS);
    }

    /**
     * 网络连接失败！
     */
    @ExceptionHandler(value = {ConnectException.class})
    @ResponseBody
    @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
    public Result<Object> connect(ConnectException e) {
        log.error("请求异常{}", e.getMessage());
        return Result.of(ResultCode.EXCEPTION_CONNECTION_ERROR);
    }

    /**
     * Http消息不可读异常。
     * 1. 缺少请求体
     * 2. 无效格式异常
     * 3. Json解析异常（非法Json格式）
     */
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(HttpMessageNotReadableException.class)
    public Result<Object> handleHttpMessageNotReadableException(HttpMessageNotReadableException e) {
        String message = e.getMessage();
        return Result.error("解析或读取请求体异常：" + message);
    }

    /**
     * 请求参数错误
     */
    @ResponseBody
    @ResponseStatus(value = HttpStatus.BAD_REQUEST)
    @ExceptionHandler(value = {BindException.class})
    public Result<Object> badRequest(BindException e) {
        log.error("请求异常" + e.getMessage());

        String errorMessage = e.getAllErrors()
                .stream()
                .map(err -> {
                    String errMsg = "";
                    if (err instanceof FieldError) {
                        errMsg += "字段:" + ((FieldError) err).getField() + "; ";
                        errMsg += "值:" + ((FieldError) err).getRejectedValue() + "; ";
                    }
                    errMsg += "错误:" + err.getDefaultMessage();
                    return errMsg;
                })
                .collect(Collectors.joining("\n"));

        return Result.error(errorMessage);
    }

    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(MissingServletRequestParameterException.class)
    public Result<Object> handleHttpMessageNotReadableException(MissingServletRequestParameterException e) {
        String parameterName = e.getParameterName();
        return Result.of(ResultCode.IN_PARAMETERS_ERROR, "请求参数" + parameterName + "不能为空");
    }

    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
    public Result<Object> handleHttpMessageNotReadableException(MethodArgumentTypeMismatchException e) {
        return Result.of(ResultCode.IN_PARAMETERS_ERROR, "请求参数" + e.getName() + "类型错误");
    }
}
